Системное программирование

Прикладной интерфейс для обработки пользовательского ввода

Системное программирование

Обработка пользовательского ввода — это одна из ключевых задач при разработке приложений. Пользовательский ввод может поступать от различных устройств, таких как клавиатура, мышь, сенсорный экран, и даже от голосовых команд. В Windows для обработки пользовательского ввода используется API, который предоставляет функции и сообщения для работы с этими устройствами.

Пользовательский ввод
Системное программирование

1. Обработка ввода с клавиатуры

Клавиатурный ввод обрабатывается с помощью сообщений WM_KEYDOWN, WM_KEYUP, WM_CHAR и других.

1.1. Сообщения клавиатуры

  • WM_KEYDOWN: генерируется при нажатии клавиши.
  • WM_KEYUP: генерируется при отпускании клавиши.
  • WM_CHAR: генерируется при вводе символа (с учетом раскладки клавиатуры).
Пользовательский ввод
Системное программирование

Пример обработки клавиатурного ввода:

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
        case WM_KEYDOWN:
            MessageBox(hwnd, "Клавиша нажата", "Клавиатура", MB_OK);
            break;
        case WM_CHAR:
            if (wParam == 'A') {
                MessageBox(hwnd, "Нажата клавиша 'A'", "Клавиатура", MB_OK);
            }
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}
Пользовательский ввод
Системное программирование

1.2. Параметры сообщений клавиатуры

  • WPARAM: виртуальный код клавиши (Virtual Key Code). Например, VK_SPACE для пробела, VK_RETURN для Enter.
  • LPARAM: содержит дополнительную информацию, такую как:
    • Повторение нажатия (биты 0–15).
    • Скан-код клавиши (биты 16–23).
    • Флаги расширенных клавиш (бит 24).
    • Состояние клавиш-модификаторов (Alt, Ctrl, Shift) (биты 29–31).
Пользовательский ввод
Системное программирование

Пример обработки WM_KEYDOWN:

case WM_KEYDOWN:
    if (wParam == VK_SPACE) {
        MessageBox(hwnd, "Пробел нажат", "Клавиатура", MB_OK);
    }
    break;
Пользовательский ввод
Системное программирование

1.3. Функции для работы с клавиатурой

  • GetAsyncKeyState: проверяет состояние клавиши (нажата/не нажата).
  • GetKeyboardState: получает состояние всех клавиш клавиатуры.

Пример использования GetAsyncKeyState:

if (GetAsyncKeyState(VK_SPACE) {
    MessageBox(hwnd, "Пробел нажат", "Клавиатура", MB_OK);
}
Пользовательский ввод
Системное программирование

2. Обработка ввода с мыши

Мышиный ввод обрабатывается с помощью сообщений, таких как WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_RBUTTONDOWN и других.

2.1. Сообщения мыши

  • WM_MOUSEMOVE: генерируется при перемещении мыши.
  • WM_LBUTTONDOWN: генерируется при нажатии левой кнопки мыши.
  • WM_RBUTTONDOWN: генерируется при нажатии правой кнопки мыши.
  • WM_MOUSEWHEEL: генерируется при прокрутке колеса мыши.
Пользовательский ввод
Системное программирование

Пример обработки мышиного ввода:

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
        case WM_LBUTTONDOWN:
            MessageBox(hwnd, "Левая кнопка мыши нажата", "Мышь", MB_OK);
            break;
        case WM_RBUTTONDOWN:
            MessageBox(hwnd, "Правая кнопка мыши нажата", "Мышь", MB_OK);
            break;
        case WM_MOUSEMOVE: {
            int x = LOWORD(lParam);
            int y = HIWORD(lParam);
            char buffer[50];
            sprintf(buffer, "Мышь: X=%d, Y=%d", x, y);
            SetWindowText(hwnd, buffer);
            break;
        }
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}
Пользовательский ввод
Системное программирование

2.2. Параметры сообщений мыши

  • WPARAM: состояние клавиш-модификаторов (Ctrl, Shift, Alt) и кнопок мыши.
    • MK_LBUTTON: нажата левая кнопка мыши.
    • MK_RBUTTON: нажата правая кнопка мыши.
    • MK_MBUTTON: нажата средняя кнопка мыши.
    • MK_CONTROL: нажата клавиша Ctrl.
    • MK_SHIFT: нажата клавиша Shift.
  • LPARAM: координаты курсора (X и Y) относительно верхнего левого угла клиентской области окна.
    • LOWORD(lParam): координата X.
    • HIWORD(lParam): координата Y.
Пользовательский ввод
Системное программирование

Пример обработки WM_MOUSEMOVE:

case WM_MOUSEMOVE: {
    int x = LOWORD(lParam);
    int y = HIWORD(lParam);
    char buffer[50];
    sprintf(buffer, "Мышь: X=%d, Y=%d", x, y);
    SetWindowText(hwnd, buffer);
    break;
}
Пользовательский ввод
Системное программирование

2.3. Сообщение WM_MOUSEWHEEL

  • WPARAM:
    • HIWORD(wParam): значение прокрутки (положительное — вверх, отрицательное — вниз).
    • LOWORD(wParam): состояние клавиш-модификаторов.
  • LPARAM: координаты курсора (X и Y) в экранных координатах.
Пользовательский ввод
Системное программирование

Пример обработки WM_MOUSEWHEEL:

case WM_MOUSEWHEEL: {
    int delta = GET_WHEEL_DELTA_WPARAM(wParam); // Значение прокрутки
    if (delta > 0) {
        MessageBox(hwnd, "Прокрутка вверх", "Мышь", MB_OK);
    } else {
        MessageBox(hwnd, "Прокрутка вниз", "Мышь", MB_OK);
    }
    break;
}
Пользовательский ввод
Системное программирование

2.4. Функции для работы с мышью

  • GetCursorPos: получает текущие координаты курсора.
  • SetCursorPos: устанавливает позицию курсора.

Пример использования GetCursorPos:

POINT pt;
GetCursorPos(&pt);
char buffer[50];
sprintf(buffer, "Курсор: X=%d, Y=%d", pt.x, pt.y);
MessageBox(hwnd, buffer, "Мышь", MB_OK);
Пользовательский ввод
Системное программирование

3. Обработка сенсорного ввода

Сенсорный ввод обрабатывается с помощью сообщений, таких как WM_TOUCH, и функций, таких как GetTouchInputInfo.

3.1. Сообщения сенсорного ввода

  • WM_TOUCH: генерируется при касании экрана.

Параметры сообщения WM_TOUCH:

  • WPARAM: количество точек касания.
  • LPARAM: дескриптор структуры HTOUCHINPUT, содержащей информацию о касаниях.
Пользовательский ввод
Системное программирование

Пример обработки сенсорного ввода:

case WM_TOUCH: {
    UINT inputCount = LOWORD(wParam);
    HTOUCHINPUT hTouchInput = (HTOUCHINPUT)lParam;
    TOUCHINPUT* pTouchInputs = new TOUCHINPUT[inputCount];
    if (GetTouchInputInfo(hTouchInput, inputCount, pTouchInputs, sizeof(TOUCHINPUT))) {
        for (UINT i = 0; i < inputCount; i++) {
            int x = pTouchInputs[i].x / 100;
            int y = pTouchInputs[i].y / 100;
            char buffer[50];
            sprintf(buffer, "Касание: X=%d, Y=%d", x, y);
            MessageBox(hwnd, buffer, "Сенсорный ввод", MB_OK);
        }
    }
    delete[] pTouchInputs;
    CloseTouchInputHandle(hTouchInput);
    break;
}
Пользовательский ввод
Системное программирование

4. Обработка голосового ввода

Голосовой ввод может быть обработан с помощью API распознавания речи, такого как Windows Speech Recognition или Microsoft Speech API (SAPI).

Пользовательский ввод
Системное программирование

4.1. Использование SAPI

Пример инициализации распознавания речи:

#include <sapi.h>

ISpRecognizer* pRecognizer = NULL;
CoInitialize(NULL);
CoCreateInstance(CLSID_SpSharedRecognizer, NULL, CLSCTX_ALL, IID_ISpRecognizer, (void**)&pRecognizer);

ISpRecoContext* pRecoContext = NULL;
pRecognizer->CreateRecoContext(&pRecoContext);

pRecoContext->SetNotifyWindowMessage(hwnd, WM_USER, 0, 0);
pRecoContext->SetInterest(SPFEI(SPEI_RECOGNITION), SPFEI(SPEI_RECOGNITION));

ISpRecoGrammar* pGrammar = NULL;
pRecoContext->CreateGrammar(0, &pGrammar);
pGrammar->LoadDictation(NULL, SPLO_STATIC);
pGrammar->SetDictationState(SPRS_ACTIVE);
Пользовательский ввод
Системное программирование

5. Пример программы для обработки пользовательского ввода

Рассмотрим пример программы, которая обрабатывает клавиатурный и мышиный ввод.

Пользовательский ввод
Системное программирование

5.1. Код программы (main.c)

#include <windows.h>
#include <stdio.h>

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
        case WM_KEYDOWN:
            MessageBox(hwnd, "Клавиша нажата", "Клавиатура", MB_OK);
            break;
        case WM_CHAR:
            if (wParam == 'A') {
                MessageBox(hwnd, "Нажата клавиша 'A'", "Клавиатура", MB_OK);
            }
            break;
        case WM_LBUTTONDOWN:
            MessageBox(hwnd, "Левая кнопка мыши нажата", "Мышь", MB_OK);
            break;
        case WM_RBUTTONDOWN:
            MessageBox(hwnd, "Правая кнопка мыши нажата", "Мышь", MB_OK);
            break;
        case WM_MOUSEMOVE: {
            int x = LOWORD(lParam);
            int y = HIWORD(lParam);
            char buffer[50];
            sprintf(buffer, "Мышь: X=%d, Y=%d", x, y);
            SetWindowText(hwnd, buffer);
            break;
        }
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

Пользовательский ввод
Системное программирование

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    WNDCLASS wc = {0};
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = "MyWindowClass";
    RegisterClass(&wc);

    HWND hwnd = CreateWindow("MyWindowClass", "Обработка ввода", WS_OVERLAPPEDWINDOW,
                             CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, NULL, NULL, hInstance, NULL);

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}
Пользовательский ввод